package org.etherframework.tests.features.command
{
	import org.etherframework.IEther;
	import org.etherframework.common.command.CommandState;
	import org.etherframework.common.command.ICommands;
	import org.etherframework.core.IModule;
	import org.etherframework.dependency.IDependencies;
	import org.etherframework.tests.features.command.commands.ErrorReactiveCommand;
	import org.etherframework.tests.features.command.commands.GestureCommand;
	import org.etherframework.tests.features.command.commands.MyController;
	import org.etherframework.tests.features.command.commands.SampleReactiveCommand;
	import org.etherframework.tests.features.command.commands.UpdateItemCommand;
	import org.etherframework.tests.features.command.events.UpdateItemEvent;
	import org.etherframework.tests.features.command.models.Item;
	import org.etherframework.tests.utils.TestUtility;
	import org.flexunit.async.Async;
	import org.hamcrest.assertThat;
	import org.hamcrest.core.not;
	import org.hamcrest.object.equalTo;
	import org.hamcrest.object.instanceOf;
	import org.hamcrest.object.notNullValue;
	import org.hamcrest.object.nullValue;

	public class when_handling_command_states
	{
		private static var _testUtility:TestUtility = new TestUtility();
		private static var _module:IModule;
		private static var _ether:IEther;
		private static var _c:ICommands;
		private static var _d:IDependencies;
		private static var _dispatchedEvent:UpdateItemEvent;
		private static var _controller:MyController;
		
		[BeforeClass]
		public static function setUpBeforeClass():void
		{
			_module = _testUtility.createModule();
			_c = _module.commands;
			_d = _module.dependencies;
			_ether = _module.ether;
			
			_d.addClass(UpdateItemCommand);
			_d.addClass(ErrorReactiveCommand);
			_d.addClass(SampleReactiveCommand);
			_d.addSingleton(MyController);
			
			_controller = _module.ether.dependencies.getInstance(MyController) as MyController;
		}
		
		[AfterClass]
		public static function tearDownAfterClass():void
		{
			_testUtility.dispose();
		}
		
		[Test(order=1, async)]
		public function it_should_be_handled():void
		{
			// Arrange
			var executeState:CommandState;
			var completeState:CommandState;
			
			_ether.commands.addCommandHandler(_controller.getSampleReactiveCommand, 
				function(state:CommandState):void 
				{
					if (state.state == CommandState.EXECUTE)
						executeState = state;
					else if (state.state == CommandState.COMPLETE)
						completeState = state;
					
				}, Vector.<String>([CommandState.EXECUTE, CommandState.COMPLETE]));
			
			// Act
			_controller.getSampleReactiveCommand().execute();
			
			Async.delayCall(this, function():void
			{
				// Assert
				assertThat(executeState, notNullValue());
				assertThat(completeState, notNullValue());
				assertThat(executeState.command, instanceOf(SampleReactiveCommand));
				assertThat(completeState.command, instanceOf(SampleReactiveCommand));
				assertThat(executeState.data, nullValue());
				assertThat(completeState.data, nullValue());
				assertThat(executeState.error, nullValue());
				assertThat(completeState.error, nullValue());
				
			}, 100);
		}
		
		
		[Test(order=2, async)]
		public function it_should_be_handled_when_one_handler_removed():void
		{
			// Arrange
			var executeState:CommandState;
			var completeState:CommandState;
			
			var handler:Function = function(state:CommandState):void 
			{
				if (state.state == CommandState.EXECUTE)
					executeState = state;
				else if (state.state == CommandState.COMPLETE)
					completeState = state;
			};
			
			_module.ether.commands.addCommandHandler(_controller.getSampleReactiveCommand, 
				handler, Vector.<String>([CommandState.EXECUTE, CommandState.COMPLETE]));
			
			// Act
			_module.ether.commands.removeCommandHandler(_controller.getSampleReactiveCommand, handler, 
				Vector.<String>([CommandState.EXECUTE]));
			_controller.getSampleReactiveCommand().execute();
			
			Async.delayCall(this, function():void
			{
				// Assert
				assertThat(executeState, nullValue());
				assertThat(completeState, notNullValue());
				
			}, 100);
		}
		
		[Test(order=3, async)]
		public function it_should_be_not_be_handled_when_all_handlers_removed():void
		{
			// Arrange
			var executeState:CommandState;
			var completeState:CommandState;
			
			var handler:Function = function(state:CommandState):void 
			{
				if (state.state == CommandState.EXECUTE)
					executeState = state;
				else if (state.state == CommandState.COMPLETE)
					completeState = state;
			};
			
			_module.ether.commands.addCommandHandler(_controller.getSampleReactiveCommand, 
				handler, Vector.<String>([CommandState.EXECUTE, CommandState.COMPLETE]));
			
			// Act
			_module.ether.commands.removeCommandHandler(_controller.getSampleReactiveCommand, handler, 
				Vector.<String>([CommandState.EXECUTE, CommandState.COMPLETE]));
			_controller.getSampleReactiveCommand().execute();
			
			Async.delayCall(this, function():void
			{
				// Assert
				assertThat(executeState, nullValue());
				assertThat(completeState, nullValue());
				
			}, 100);
		}
		
		[Test(order=4, async)]
		public function it_should_be_handled_with_error():void
		{
			// Arrange
			var completeState:CommandState;
			
			var handler:Function = function(state:CommandState):void 
			{
				completeState = state;
			};
			
			_module.ether.commands.addCommandHandler(_controller.getErrorReactiveCommand, 
				handler, Vector.<String>([CommandState.COMPLETE]));
			
			// Act
			_controller.getErrorReactiveCommand().execute();
			
			Async.delayCall(this, function():void
			{
				// Assert
				assertThat(completeState, notNullValue());
				assertThat(completeState.error, notNullValue());
				assertThat(completeState.error.message, equalTo("Salute!"));
				
			}, 100);
		}
		
	}
}